package com.maxcion.scalelayoutmanager.form

import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import java.lang.RuntimeException

class FormLayoutManager<T> private constructor(private val maxColumnCount  :Int) :
    RecyclerView.LayoutManager() {

    private var mItemHeight: Int = 0
    private var mItemWidth: Int = 0
    private var mHorizontalDistance = 0
    private var mVerticalDistance = 0

//    private constructor(config : Builder<T>)

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
    }

    override fun onLayoutChildren(recycler: RecyclerView.Recycler?, state: RecyclerView.State?) {
        recycler?.let {

            if (itemCount == 0) {
                detachAndScrapAttachedViews(recycler)
            }
            if (mHorizontalDistance == 0 && mVerticalDistance == 0) {
                recycler.getViewForPosition(0).let {
                    addView(it)
                    measureChildWithMargins(it, 0, 0)
                    mItemWidth = it.measuredWidth
                    mItemHeight = it.measuredHeight
                }
            }

            fill(recycler)
            recycleChildren(recycler)
        }
    }

    private fun fill(recycler: RecyclerView.Recycler) {
        detachAndScrapAttachedViews(recycler)

        val lineNum = mVerticalDistance / mItemHeight
        val columnNum = mHorizontalDistance / mItemWidth

        val firstChild = lineNum * maxColumnCount + columnNum
        val xOffset = mHorizontalDistance % mItemWidth
        val yOffset = mVerticalDistance % mItemHeight

        var tempChildHorizontalIndex = 0
        var tempChildVerticalIndex = 0

        var left = 0
        var right = 0
        var top = 0
        var bottom = 0

        var index = firstChild

        while (index < itemCount) {
            if (columnNum + tempChildHorizontalIndex < maxColumnCount) {


            } else {
                tempChildHorizontalIndex = 0
                ++tempChildVerticalIndex
                index += columnNum
                if (index >= itemCount) {
                    continue
                }
            }

            left = -xOffset + tempChildHorizontalIndex * mItemWidth
            right = left + mItemWidth
            top = -yOffset + tempChildVerticalIndex * mItemHeight
            bottom = top + mItemHeight
            if (top > height) {
                return
            }
            tempChildHorizontalIndex++

            if (right < 0 ||
                left > width
            ) {
                index++
                continue
            }
            val viewForPosition = recycler.getViewForPosition(index)
            addView(viewForPosition)
            layoutDecoratedWithMargins(viewForPosition, left, top, right, bottom)
            index++
        }
    }

    override fun canScrollHorizontally(): Boolean {
        return true
    }

    override fun canScrollVertically(): Boolean {
        return true
    }

    override fun scrollHorizontallyBy(
        dx: Int,
        recycler: RecyclerView.Recycler?,
        state: RecyclerView.State?
    ): Int {
        var newDx = dx
        if (mHorizontalDistance + dx > getMaxScrollX()) {
            newDx = 0
        }

        if (mHorizontalDistance + dx < 0) {
            newDx = 0
        }

        mHorizontalDistance += newDx

        fill(recycler!!)
        recycleChildren(recycler)
        return newDx
    }

    override fun scrollVerticallyBy(
        dy: Int,
        recycler: RecyclerView.Recycler?,
        state: RecyclerView.State?
    ): Int {

        var newDy = dy
        if (mVerticalDistance + dy > getMaxScrollY()) {
            newDy = 0
        }

        if (mVerticalDistance + dy < 0) {
            newDy = 0
        }

        mVerticalDistance += newDy

        fill(recycler!!)
        recycleChildren(recycler)

        return newDy
    }


    private fun getMaxScrollX() = mItemWidth * maxColumnCount.coerceAtMost(itemCount) - width

    private fun getMaxScrollY() = mItemHeight * (itemCount / maxColumnCount + 1) - height
    private fun recycleChildren(recycler: RecyclerView.Recycler) {
        val scrapList: List<RecyclerView.ViewHolder> = recycler.getScrapList()
        for (i in scrapList.indices) {
            if (i < scrapList.size) {
                val holder = scrapList[i]
                removeAndRecycleView(holder.itemView, recycler)
            }
        }
    }

    class Builder<T> {
        var recyclerView: RecyclerView? = null
        var horizontalTitles = mutableListOf<IHorizontalTitleItem>()
        var verticalTitles = mutableListOf<IVerticalTitleItem>()
        var contentLines = mutableListOf<T>()
        var contentConvert: ItemViewConvert<T>? = null
        var emptyTitleLayoutId = -1
        var horizontalTitleLayoutId = -1
        var verticalTitleLayoutId = -1
        var contentLayoutId = -1
        var maxColumnCount = 1

        public fun setMaxColumnCount(count: Int) = also {
            maxColumnCount = count
        }

        public fun setContentLines(data: MutableList<T>) = also {
            contentLines = data
        }

        public fun setHorizontalTitles(data: MutableList<IHorizontalTitleItem>) = also {
            horizontalTitles = data
        }

        public fun setVerticalTitles(data: MutableList<IVerticalTitleItem>) = also {
            verticalTitles = data
        }

        public fun setContentConvert(convert: ItemViewConvert<T>) = also {
            contentConvert = convert
        }

        public fun setHorizontalTitleLayoutId(id: Int) = also {
            horizontalTitleLayoutId = id
        }

        public fun setVerticalTitleLayoutId(id: Int) = also {
            verticalTitleLayoutId = id
        }

        public fun setContentLayoutId(id: Int) = also {
            contentLayoutId = id
        }

        public fun setEmptyTitleLayoutId(id: Int) = also {
            emptyTitleLayoutId = id
        }

        public fun setRecyclerView(rv: RecyclerView) = also {
            recyclerView = rv
        }


        fun create() : FormLayoutManager<T>{
            if (verticalTitles.isNotEmpty() && verticalTitleLayoutId <= 0) {
                throw RuntimeException("If you want set verticalTitles , please set  verticalTitleLayoutId first")
            }

            if (horizontalTitles.isNotEmpty() && horizontalTitleLayoutId <= 0) {
                throw RuntimeException("If you want set horizontalTitles , please set  horizontalTitleLayoutId first")
            }

            if (verticalTitleLayoutId > 0 && horizontalTitleLayoutId > 0 && emptyTitleLayoutId < 0) {
                throw RuntimeException("If you want set verticalTitleLayoutId and  horizontalTitleLayoutId , please set  emptyTitleLayoutId first")
            }


            if (recyclerView == null) {
                throw RuntimeException("you have not set recyclerview")
            }

            var adapterConvert: IAdapterConvert? = null

            if (horizontalTitles.size > 0 && verticalTitles.size == 0) {
                adapterConvert = OnlyHorizontalAdapterConvert<T>(this)
            } else if (horizontalTitles.size == 0 && verticalTitles.size > 0) {
                adapterConvert = OnlyVerticalAdapterConvert<T>(this)
            } else {
                adapterConvert = FullTitleAdapterConvert<T>(this)
            }
            recyclerView?.adapter = FormAdapter(adapterConvert, this)
            val layoutManager = FormLayoutManager<T>(maxColumnCount)
            recyclerView?.layoutManager = layoutManager
            return layoutManager
        }

    }
}